import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.TreeMap;
import java.util.Map;
import java.util.ArrayList;

//Интерфейс преобразования строки в любой конструируемый объект
interface IParse {
    Object Parse(String str);
}

/*
* Парсит и хранит данные из CSV файла.
* Должно гарантироваться, что файл существует.
* Выбросит IOException, если файл некорректен.
*
* Есть мааааааленькая неуверенность, как метод getName() поведёт себя
*  не на POSIX-совместимых системах.
*/
public class FileCSV {
    private final String path;
    private final String name;
    private final String[] head;
    private final ArrayList<Tuple> formattedBase = new ArrayList<>();
    private final String[] template; //Шаблон Tuple, который будет содержать данные
    //по строке. Требуется из-за особенностей инкапсуляции Tuple.

    private final TreeMap<String, IParse> dictionary = new TreeMap<>(Map.ofEntries(
         Map.entry("Integer", Integer::parseInt),
         Map.entry("Boolean", Boolean::parseBoolean),
         Map.entry("String", (String str) -> str)
    ));

    //Парсит в зависимости от переданного типа в текстовой форме
    private Object dynamicParse(String key, String str) throws IOException {
        if (!dictionary.containsKey(key)) {
            String errLog = "Type \"" + key + "\" cannot be parsed";
            throw (new IOException("Invalid file template: " + errLog));
        }
        return dictionary.get(key).Parse(str);
    }
    private Tuple splitTheLine(String line) throws IOException {
        String[] list = line.split(",");
        if (list.length != head.length) {
            String errLog = String.format("Line %s should " +
                    "contain %d symbols", line, head.length);
            throw (new IOException("Invalid file: " + errLog));
        }
        Tuple temp = new Tuple(template);
        for (int i = 0; i < list.length; ++i) {
            temp.set(i, dynamicParse(template[i], list[i]));
        }
        return temp;
    }
    public String getName() {
        return name;
    }
    public String getPath() {
        return path;
    }
    //Конструктор берёт на себя практически всю логику.
    FileCSV(String pathFile, String[] template) throws IOException {
        this.template = template;
        path = pathFile;
        /////Ввод по стандарту UNC может быть череват
        // катастрофическими последствиями
        name = path.substring(path.lastIndexOf("/"));
        /////
        List<String> buffer = Files.readAllLines(Path.of(path));
        head = buffer.get(0).split(",");
        if (template.length != head.length) {
            String errLog = String.format("Head contains %d symbols, " +
                    "but template contains %d symbols", head.length, template.length);
            throw (new IOException("Invalid file or template: " + errLog));
        }
        for (int i = 1; i < buffer.size(); ++i) {
            formattedBase.add(splitTheLine(buffer.get(i)));
        }
    }
    public ArrayList<Tuple> getArray() {
        return formattedBase;
    }
}
